package com.mallcloud.mall.common.core.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mallcloud.mall.common.core.exception.FailException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URLDecoder;
import java.util.Map;

/**
 * 网络请求工具
 */
@Slf4j
@Service
public class HttpUtil {

	@SneakyThrows
	public <T> T exchange(String url, Method method,
						  Map<String, String> headers,
						  Map<String, Object> query, Object body,
						  Class<T> resClass) {

		return exchange(url, method, headers, query, body, false, resClass);
	}

	@SneakyThrows
	public <T> T exchange(String url, Method method,
						  Map<String, String> headers,
						  Map<String, Object> query, Object body,
						  Boolean resDecoder, Class<T> resClass) {
		UriComponentsBuilder uri = UriComponentsBuilder.fromHttpUrl(url);
		if (CollUtil.isNotEmpty(query)) {
			for (Map.Entry<String, Object> entry : query.entrySet()) {
				uri.queryParam(entry.getKey(), entry.getValue());
			}
		}
		final HttpRequest request = cn.hutool.http.HttpUtil.createRequest(method, uri.build().toUriString());
		if (CollUtil.isNotEmpty(headers)) {
			request.headerMap(headers, true);
		}

		final String contentType = request.header(HttpHeaders.CONTENT_TYPE);

		if (body instanceof JSONObject) {
			if (StrUtil.isNotEmpty(contentType)) {
				if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(contentType)
						|| MediaType.MULTIPART_FORM_DATA_VALUE.equals(contentType)) {
					((JSONObject) body).forEach(request::form);
				}
				else {
					request.body(((JSONObject) body).toJSONString());
				}
			}
			else {
				request.body(((JSONObject) body).toJSONString());
			}
		}
		else if (body instanceof JSONArray) {
			request.body(((JSONArray) body).toJSONString());
		}
		else if (body instanceof String && MediaType.APPLICATION_XML_VALUE.equals(contentType)) {
			request.body(body.toString());
		}

		final HttpResponse res;
		try {
			res = request.execute();
		}
		catch (RestClientResponseException e) {
			throw new FailException(String.format("请求【%s】返回状态非200：%s", url, e.getRawStatusCode()));
		}
		if (!res.isOk()) {
			throw new Exception("请求失败,错误码:" + res.getStatus());
		}
		if (res.body() == null) {
			return null;
		}

		String response = resDecoder ? URLDecoder.decode(res.body(), "UTF-8") : res.body();
		T t;
		try {
			if (resClass.equals(String.class)) {
				t = (T) response;
			}
			else {
				t = JSONObject.parseObject(response, resClass);
			}
		}
		catch (Exception e) {
			log.error("返回数据JSON转换异常:{}", response);
			throw new FailException(String.format("返回数据JSON转换异常:%s", response), e);
		}
		return t;
	}
}
